/**
 * GameView class, super class for every view in the game. subclasses should override update and paint methods according to their own function.
 * 
 **/
package com.example.gametestproject;
import java.util.Collections;
import java.util.Comparator;
import java.util.Vector;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.view.GestureDetector.OnGestureListener;
import android.app.Application;

import com.example.gametestproject.RenderThread;
import com.example.gametestproject.MapManager;

import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.xxxx.game.*;

public class GameView extends SurfaceView implements SurfaceHolder.Callback, OnGestureListener
{
	private Vector<ISprite> mSprites = null;
	private IGameMode mGameMode = new ClassicMode();
	private GameLevel mLevel = null;
	
	public RenderThread mThread;
	public boolean mIsGameOver = true;
	private GestureDetector gd = new GestureDetector(this);
	//control buttons
	UIControl cb_scoreLabel;
	UIControl cb_levelLabel;
	UIControl cb_pauseBtn;
	UIControl cb_process;
	
	public GameView(Context context)
	{
		super(context);
		SurfaceHolder lSurfaceHolder = this.getHolder();
		lSurfaceHolder.addCallback(this);
        this.newGame();
//		this.mThread = new RenderThread(lSurfaceHolder, this, null);
//		ResourceManager manager = ResourceManager.getInstance();
//		//manager.setContext(context);
	}

	public IGameMode resetGameMode(IGameMode newGameMode)
	{
		IGameMode bk = mGameMode;
		mGameMode = newGameMode;
		return bk;
	}

	
	//update sprites state , game logic should be update from here
	public void update()
	{
		int vinished_count = 0;
		Vector<ISprite> toRemove = new Vector<ISprite>();
		if (this.mGameMode != null && !this.mIsGameOver)
		{
			vinished_count = mGameMode.vanishSpites(this.mLevel.mMatrix);
			Vector<ISprite> toAdd = new Vector<ISprite>();
			mGameMode.insertRemoveJewels(this.mLevel.mMatrix, toAdd, toRemove);
			this.mSprites.addAll(toAdd);
			//this.mSprites.clear();
			//this.mSprites = this.mMatrix.toContainer();
		}
		
		for (ISprite x : this.mSprites)
		{
			if (x != null && !x.isLiving())
			{
				toRemove.add(x);
				Log.i("jewel", "remove dead jewels!");
			}
		}
		
		//int count = this.mSprites.size();

		// remove all dead object
		this.mSprites.removeAll(toRemove);
		//Log.i("jewel", String.format("%d - %d = %d", count, toRemove.size(), this.mSprites.size()));
		
		if (this.mGameMode != null && vinished_count == 0)
		{
			if (this.mGameMode.isGameOver(this.mLevel.mMatrix))
			{
				Log.i("main", "game over!");
				// gameover
				this.mIsGameOver = true;
				if (mThread != null) mThread.setRunning(false);
				Message gameOverMsg = new Message();
				mHandler.sendMessage(gameOverMsg);
			}
		}

		if(this.mGameMode.isLevelOver())
		{		
			Log.i("GameView", "score: " + this.mGameMode.mLevel.getUserScore());
			Log.i("main", "level over!");
			if (mThread != null) mThread.setRunning(false);
			this.mGameMode.gotoNextLevel();
			this.mSprites = this.mGameMode.mLevel.mMatrix.toContainer();
			if (mThread != null) mThread.setRunning(true);
		}
		
//		boolean hastest = false;
//		for (ISprite sprite : this.mSprites)
//		{
//			if (sprite instanceof ShaderTextSprite)
//			{
//				hastest = true;
//				break;
//			}
//		}
//		if (!hastest)
//		{
//			mSprites.add(new ShaderTextSprite("Good", new PointF(10, 10), new PointF(200, 200)));
//		}
		
		// sort all sprite by its zorder
		Collections.sort(this.mSprites, 
				new Comparator<ISprite>()
				{
					@Override
					public int compare(ISprite s1, ISprite s2)
					{
						return s1.getZOrder() - s2.getZOrder();
					}
				});
		
		for (int i = 0; i < mSprites.size(); ++ i)
		{
			try {
				this.mSprites.get(i).update();
			} catch(Exception e)
			{
				Log.i("GameView", "Error in update sprite[" + i + "] " + e.getMessage());
			}
		}
	}
	
	private Handler mHandler = new Handler()
	{
		@Override
		public void handleMessage(Message paramMessage)
		{
			new AlertDialog.Builder(GameView.this.getContext()) 
				.setTitle("GameOver")
				.setMessage("Restart again�� Select no to quit")
				.setPositiveButton("Yes", new DialogInterface.OnClickListener()
				{
					@Override
					public void onClick(DialogInterface dialog, int arg)
					{
						Log.i("main", "yes!");
						newGame();
					}
				})
			.setNegativeButton("No", new DialogInterface.OnClickListener()
				{
					@Override
					public void onClick(DialogInterface dialog, int arg)
					{
						Log.i("main", "no!");
						//mThread.stop();
						System.exit(0);
					}
				})
			.show();
		}
	};
	
	private FPSTestSprite mFPSSprite = new FPSTestSprite();
	public FPSTestSprite getFPSSprite()
	{
		return mFPSSprite;
	}
	
	//paint sprites
	public void paint(Canvas canvas)
	{
		//draw sprite here
		canvas.drawBitmap(ResourceManager.getInstance().getBkImage(), 0, 0, new android.graphics.Paint());
		this.cb_levelLabel.paint(canvas);
		this.cb_pauseBtn.paint(canvas);
		this.cb_scoreLabel.paint(canvas);
		this.cb_process.paint(canvas);
		for(int i = 0; i < this.mSprites.size(); ++ i)
		{
			this.mSprites.get(i).paint(canvas);
		}
		
//		if (mGameMode != null && mMatrix != null && mGameMode.getSelectedJewel(mMatrix) != null)
//		{
//			if (++ mShowRectHelper > 10)
//			{
//				mShowRectHelper = 0;
//			}
//			
//			if ((mShowRectHelper / 5) % 2 == 0)
//			{ // paint a rect 
//				JewelSprite js = mGameMode.getSelectedJewel(mMatrix);
//				Paint paint = new Paint();
//				paint.setColor(Color.rgb(255, 0, 0));
//				paint.setStrokeWidth(2);
//				paint.setStyle(Style.STROKE);
//				canvas.drawRect(js.getRect(), paint);
//			}
//		}
	}
	
	public void newGame()
	{
		MapManager lpMapManager = MapManager.getInstance();
		GameLevel gl = lpMapManager.createNewLevel(0, 0);
		this.mGameMode.setGameLevel(gl);
		mSprites = this.mGameMode.getLevel().mMatrix.toContainer();//gl.mMatrix.toContainer();
		mSprites.add(mFPSSprite); // add fps sprite
		mLevel = gl;
		this.initControls();
        this.mIsGameOver = false;
		this.setKeepScreenOn(true);
	}

	private void initControls()
	{
		ResourceManager rManager = ResourceManager.getInstance();
		this.cb_scoreLabel = new UIControl(rManager.getScoreImg(), null, rManager.getScorePos());
		this.cb_levelLabel = new UIControl(rManager.getLevelImg(), null, rManager.getLevelPos());
		this.cb_pauseBtn = new UIControl(rManager.getPauseImg(), rManager.getStartImg(), rManager.getPausePos());
		this.cb_process = new UIControl(rManager.getProcessImg(), null, rManager.getProcessPos());
	}

    public void pause()
    {
        if (this.mThread != null)
            this.mThread.setRunning(false);

    }
    public void resume()
    {
        if (this.mThread != null)
            this.mThread.setRunning(true);
    }
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
	{
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder)
	{
        try {
            if (this.mThread == null)
            {
                GameView.this.mThread = new RenderThread(GameView.this.getHolder(), GameView.this, null);
                GameView.this.mThread.setRunning(true);
                GameView.this.mThread.start();
            }
            else
            {
                this.mThread.setRunning(true);
                this.mThread.start();
            }


        }
        catch (Exception e)
        {
            Log.i("view", "create new thread failed, " + e.getMessage());
        }
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder)
	{
//		boolean retry = true;
//		this.mThread.setRunning(false);
//		while(retry)
//		{
//			try
//			{
//				this.mThread.join();
//				retry = false;
//			} catch(Exception e)
//			{
//				Log.i("GameView", "Error in surfaceDestroyed of GameView");
//			}
//		}

	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event)
	{

		if (gd != null)
		{
			if(this.mThread.isRunning() || this.cb_pauseBtn.containsPoint(event.getX(), event.getY()))
				gd.onTouchEvent(event);
		}
		return true;
	}

	@Override
	public boolean onDown(MotionEvent e)
	{
		// TODO Auto-generated method stub
		if(this.cb_pauseBtn.containsPoint(e.getX(), e.getY()))
		{
			this.cb_pauseBtn.setPressed(!cb_pauseBtn.isPressed());
		}
		Log.i("TouchEvent", "onDown");
		return true;
	}

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
			float velocityY)
	{
		Log.i("TouchEvent", "onFling");
		if (mGameMode != null)
		{
			float dx = e2.getX() - e1.getX();
			float dy = e2.getY() - e1.getY();
			
			if (Math.abs(dx) > ResourceManager.mSpriteWidth / 2 || Math.abs(dy) > ResourceManager.mSpriteHeight / 2)
			{
				if (Math.abs(dx) > Math.abs(dy))
				{
					MotionType type = dx > 0 ? MotionType.Motion_Right : MotionType.Motion_Left;
					mGameMode.doAction(mLevel.mMatrix, new PointF(e1.getX(), e1.getY()), type);
				}
				else
				{
					MotionType type = dy > 0 ? MotionType.Motion_Down : MotionType.Motion_Up;
					mGameMode.doAction(mLevel.mMatrix, new PointF(e1.getX(), e1.getY()), type);
				}
				return true;
			}
			else return false;
		}
		return true;
	}

	@Override
	public void onLongPress(MotionEvent e)
	{
		Log.i("TouchEvent", "onLongPress");
		// TODO Auto-generated method stub
		if (mGameMode != null)
		{
			mGameMode.doAction(mLevel.mMatrix, new PointF(e.getX(), e.getY()), MotionType.Motion_Click);
		}
	}

	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
			float distanceY)
	{
		Log.i("TouchEvent", "onScroll");
		// TODO Auto-generated method stub
		if (mGameMode != null)
		{
			float dx = e2.getX() - e1.getX();
			float dy = e2.getY() - e1.getY();
			
			if (Math.abs(dx) > ResourceManager.mSpriteWidth / 2 || Math.abs(dy) > ResourceManager.mSpriteHeight / 2)
			{
				if (Math.abs(dx) > Math.abs(dy))
				{
					MotionType type = dx > 0 ? MotionType.Motion_Right : MotionType.Motion_Left;
					mGameMode.doAction(mLevel.mMatrix, new PointF(e1.getX(), e1.getY()), type);
				}
				else
				{
					MotionType type = dy > 0 ? MotionType.Motion_Down : MotionType.Motion_Up;
					mGameMode.doAction(mLevel.mMatrix, new PointF(e1.getX(), e1.getY()), type);
				}
				return true;
			}
			else return false;
		}
		
		return true;
	}

	@Override
	public void onShowPress(MotionEvent e)
	{
		// TODO Auto-generated method stub
		Log.i("TouchEvent", "onShowPress");
	}

	@Override
	public boolean onSingleTapUp(MotionEvent e)
	{
		Log.i("TouchEvent", "onSingleTapUp");

		if(this.cb_pauseBtn.containsPoint(e.getX(), e.getY()))
		{
			if(this.mThread.isRunning())
				this.pause();
			else
				this.resume();

		}
		if (mGameMode != null)
		{
			mGameMode.doAction(mLevel.mMatrix, new PointF(e.getX(), e.getY()), MotionType.Motion_Click);
		}
		
		
		return true;
	}
}
